#include "STLModelSlicesProducer.h"

QVector<Layer> STLModelSlicesProducer::preprocessModelDataAlongDirection(const QVector<Vertex> &stl_model_vertices, QVector3D &direction_norm)
{
    return QVector<Layer>();
}

QVector<QPair<QPair<float, float>, Edge>> STLModelSlicesProducer::preprocessModelDataAlongDirection(const QVector<Edge> &stl_model_meshes, QVector3D &direction_norm)
{
    // 归一化方向向量
    direction_norm.normalize();

    // 存储预处理后的边分区
    QVector<QPair<QPair<float, float>, Edge>> prepreprocess_edges_partitions;

    // 遍历所有边，计算投影区间
    for (const Edge& edge : stl_model_meshes)
    {
        // 计算两个顶点在方向向量上的投影值
        float a = QVector3D::dotProduct(edge.v1.pos, direction_norm);
        float b = QVector3D::dotProduct(edge.v2.pos, direction_norm);

        // 更新最高点和最低点的模长
        m_highest = std::max(m_highest, std::max(a, b));
        m_lowest = std::min(m_lowest, std::min(a, b));

        // a_i 取模型顶点，对应区间左端点
        QPair<float, float> partition = (a > b) ? QPair<float, float>(a, b) : QPair<float, float>(b, a);

        // 将区间和边存储到结果中
        prepreprocess_edges_partitions.append(qMakePair(partition, edge));
    }

    // 对区间进行排序：先按 a_i 降序排序，再按 b_i 降序排序
    std::sort(prepreprocess_edges_partitions.begin(), prepreprocess_edges_partitions.end(),
              [](const QPair<QPair<float, float>, Edge>& p1, const QPair<QPair<float, float>, Edge>& p2) {
                  // 比较 a_i
                  if (p1.first.first != p2.first.first) {
                      return p1.first.first > p2.first.first;
                  }
                  // 如果 a_i 相等，比较 b_i
                  return p1.first.second > p2.first.second;
              });

    return prepreprocess_edges_partitions;
}

QVector<Edge> binarySiftPartitions(const QVector<QPair<QPair<float, float>, Edge>>& preprocess_edges, float lambda)
{
    QVector<Edge> result;

    // 如果预处理数组为空，直接返回空结果
    if (preprocess_edges.isEmpty())
        return result;

    // 二分查找最后一个满足 a_i >= lambda 的位置
    int left = 0;
    int right = preprocess_edges.size() - 1;
    int lastValidIndex = -1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (preprocess_edges[mid].first.first >= lambda)
        {
            lastValidIndex = mid; // 记录可能的位置
            left = mid + 1;       // 继续向右查找更大的索引
        }
        else
            right = mid - 1;      // 向左查找
    }

    // 如果没有找到满足条件的区间，直接返回空结果
    if (lastValidIndex == -1)
        return result;

    // 遍历从 0 到 lastValidIndex 的区间，筛选出 b_i <= lambda 的边
    for (int i = 0; i <= lastValidIndex; ++i) {
        const auto& partition = preprocess_edges[i];
        float b_i = partition.first.second;

        if (b_i <= lambda) {
            result.append(partition.second);
        }
    }

    return result;
}

QVector<Vertex> intersectEdgesWithPlane(const QVector<Edge> &sifted_edges, const QVector3D &direction_norm, float lambda)
{
    QVector<Vertex> intersections;

    // 平面上的点 P0 = lambda * direction_norm
    QVector3D P0 = lambda * direction_norm;

    for (const Edge& edge : sifted_edges)
    {
        const QVector3D& v1 = edge.v1.pos;
        const QVector3D& v2 = edge.v2.pos;

        // 边的方向向量
        QVector3D edgeDirection = v2 - v1;

        // 计算分母：direction_norm · edgeDirection
        float denominator = QVector3D::dotProduct(direction_norm, edgeDirection);

        // 如果分母为 0，说明边与平面平行，没有交点
        if (qFuzzyIsNull(denominator)) {
            continue;
        }

        // 计算参数 t
        float t = QVector3D::dotProduct(direction_norm, P0 - v1) / denominator;

        // 如果 t 在 [0, 1] 范围内，说明交点在边上
        if (t >= 0.0f && t <= 1.0f)
        {
            // 计算交点坐标
            Vertex intersection;
            intersection.pos = v1 + t * edgeDirection;
            intersection.norm = edge.norm;

            intersections.append(intersection);
        }
    }

    return intersections;
}

// 切面法向量以及切片间隔需要配置文件提供
void STLModelSlicesProducer::generateShownVertices(const QVector<QPair<QPair<float, float>, Edge>> &preprocessed_partitions, const QVector3D& slice_norm, float stride,
                                                   QVector<Vertex>& out_intersected_points, QVector<qsizetype>& out_intersected_points_counts, QVector<float>& out_slice_lambdas)
{
    // 防止程序崩溃，如果输入不合法则默认设置为0.01f切片
    if(stride <= 0.0f)
        stride = 0.01f;

    float totalHeight = m_highest - m_lowest;
    int numSlices = static_cast<int>(std::ceil(totalHeight / stride)); // 向上取整，确保覆盖整个范围

    // 调整 stride，确保顶部和尾部都有切片
    float adjustedStride = totalHeight / numSlices;

    // 按 adjustedStride 切片
    for (int i = 0; i <= numSlices; ++i)
    {
        float currentLambda = m_highest - i * adjustedStride;

        // 确保最后一个切片是 m_lowest
        if (i == numSlices)
            currentLambda = m_lowest;

        // 二分筛边
        QVector<Edge> sifted_edges = binarySiftPartitions(preprocessed_partitions, currentLambda);

        // 计算当前切片的交点
        auto intersections = intersectEdgesWithPlane(sifted_edges, slice_norm, currentLambda);

        // 追加模型切片
        out_intersected_points.append(intersections);

        // 记录当前交点的数量
        out_intersected_points_counts.append(intersections.size());

        // 记录当前切片用的高度
        out_slice_lambdas.append(currentLambda);
    }
}
